#define SQLITE_OS_WIN

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Community.CsharpSqlite.Entity;
using DWORD = System.UInt64;
using HANDLE = System.IntPtr;


namespace Community.CsharpSqlite
{
    public partial class Sqlite3
    {
        /*
    ** 2004 May 22
    **
    ** The author disclaims copyright to this source code.  In place of
    ** a legal notice, here is a blessing:
    **
    **    May you do good and not evil.
    **    May you find forgiveness for yourself and forgive others.
    **    May you share freely, never taking more than you give.
    **
    ******************************************************************************
    **
    ** This file contains code that is specific to windows.
    *************************************************************************
    **  Included in SQLite3 port to C#-SQLite;  2008 Noah B Hart
    **  C#-SQLite is an independent reimplementation of the SQLite software library
    **
    **  SQLITE_SOURCE_ID: 2010-03-09 19:31:43 4ae453ea7be69018d8c16eb8dabe05617397dc4d
    **
    **  $Header: Community.CsharpSqlite/src/os_win_c.cs,v 6604176a7dbe 2010/03/12 23:35:36 Noah $
    *************************************************************************
    */
        //#include "sqliteInt.h"
#if SQLITE_OS_WIN
        // * This file is used for windows only */

        /*
** A Note About Memory Allocation:
**
** This driver uses malloc()/free() directly rather than going through
** the SQLite-wrappers Malloc.sqlite3Malloc()/MemPool.DbFree(db,ref  ).  Those wrappers
** are designed for use on embedded systems where memory is scarce and
** malloc failures happen frequently.  Win32 does not typically run on
** embedded systems, and when it does the developers normally have bigger
** problems to worry about than running out of memory.  So there is not
** a compelling need to use the wrappers.
**
** But there is a good reason to not use the wrappers.  If we use the
** wrappers then we will get simulated malloc() failures within this
** driver.  And that causes all kinds of problems for our tests.  We
** could enhance SQLite to deal with simulated malloc failures within
** the OS driver, but the code to deal with those failure would not
** be exercised on Linux (which does not need to malloc() in the driver)
** and so we would have difficulty writing coverage tests for that
** code.  Better to leave the code out, we think.
**
** The point of this discussion is as follows:  When creating a new
** OS layer for an embedded system, if you use this file as an example,
** avoid the use of malloc()/free().  Those routines work ok on windows
** desktops but not so well in embedded systems.
*/

        //#include <winbase.h>

#if __CYGWIN__
//# include <sys/cygwin.h>
#endif

        /*
** Macros used to determine whether or not to use threads.
*/
#if THREADSAFE
//# define SQLITE_W32_THREADS 1
#endif

        /*
** Include code that is common to all os_*.c files
*/
        //#include "os_common.h"

        /*
    ** Some microsoft compilers lack this definition.
    */
#if !INVALID_FILE_ATTRIBUTES
        //# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
        private const int INVALID_FILE_ATTRIBUTES = -1;
#endif

        /*
** Determine if we are dealing with WindowsCE - which has a much
** reduced API.
*/
#if SQLITE_OS_WINCE
//# define AreFileApisANSI() 1
//# define GetDiskFreeSpaceW() 0
#endif

        /*
** WinCE lacks native support for file locking so we have to fake it
** with some code of our own.
*/
#if SQLITE_OS_WINCE
typedef struct winceLock {
int nReaders;       /* Number of reader locks obtained */
BOOL bPending;      /* Indicates a pending lock has been obtained */
BOOL bReserved;     /* Indicates a reserved lock has been obtained */
BOOL bExclusive;    /* Indicates an exclusive lock has been obtained */
} winceLock;
#endif

        private static readonly LockingStrategy lockingStrategy = HelperMethods.IsRunningMediumTrust()
                                                                      ? new MediumTrustLockingStrategy()
                                                                      : new LockingStrategy();


        /*
    ** Forward prototypes.
    */
        //static int getSectorSize(
        //    sqlite3_vfs *pVfs,
        //    const char *zRelative     /* UTF-8 file name */
        //);

        /*
    ** The following variable is (normally) set once and never changes
    ** thereafter.  It records whether the operating system is Win95
    ** or WinNT.
    **
    ** 0:   Operating system unknown.
    ** 1:   Operating system is Win95.
    ** 2:   Operating system is WinNT.
    **
    ** In order to facilitate testing on a WinNT system, the test fixture
    ** can manually set this value to 1 to emulate Win98 behavior.
    */
#if SQLITE_TEST
    int sqlite3_os_type = 0;
#else
        private static int sqlite3_os_type;
#endif

        /*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
** or WinCE.  Return false (zero) for Win95, Win98, or WinME.
**
** Here is an interesting observation:  Win95, Win98, and WinME lack
** the LockFileEx() API.  But we can still statically link against that
** API as long as we don't call it when running Win95/98/ME.  A call to
** this routine is used to determine if the host is Win95/98/ME or
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
*/
#if SQLITE_OS_WINCE
//# define isNT()  (1)
#else
        private static bool isNT()
        {
            //if (sqlite3_os_type == 0)
            //{
            //  OSVERSIONINFO sInfo;
            //  sInfo.dwOSVersionInfoSize = sInfo.Length;
            //  GetVersionEx(&sInfo);
            //  sqlite3_os_type = sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ? 2 : 1;
            //}
            //return sqlite3_os_type == 2;
            return Environment.OSVersion.Platform >= PlatformID.Win32NT;
        }
#endif
        // * SQLITE_OS_WINCE */

        /*
** Convert a UTF-8 string to microsoft unicode (UTF-16?).
**
** Space to hold the returned string is obtained from malloc.
*/
        //static WCHAR *utf8ToUnicode(string zFilename){
        //  int nChar;
        //  WCHAR *zWideFilename;

        //  nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
        //  zWideFilename = malloc( nChar*sizeof(zWideFilename[0]) );
        //  if( zWideFilename==0 ){
        //    return 0;
        //  }
        //  nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
        //  if( nChar==0 ){
        //    free(zWideFilename);
        //    zWideFileName = "";
        //  }
        //  return zWideFilename;
        //}

        /*
    ** Convert microsoft unicode to UTF-8.  Space to hold the returned string is
    ** obtained from malloc().
    */
        //static char *unicodeToUtf8(const WCHAR *zWideFilename){
        //  int nByte;
        //  char *zFilename;

        //  nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
        //  zFilename = malloc( nByte );
        //  if( zFilename==0 ){
        //    return 0;
        //  }
        //  nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
        //                              0, 0);
        //  if( nByte == 0 ){
        //    free(zFilename);
        //    zFileName = "";
        //  }
        //  return zFilename;
        //}

        /*
    ** Convert an ansi string to microsoft unicode, based on the
    ** current codepage settings for file apis.
    **
    ** Space to hold the returned string is obtained
    ** from malloc.
    */
        //static WCHAR *mbcsToUnicode(string zFilename){
        //  int nByte;
        //  WCHAR *zMbcsFilename;
        //  int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;

        //  nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*WCHAR.Length;
        //  zMbcsFilename = malloc( nByte*sizeof(zMbcsFilename[0]) );
        //  if( zMbcsFilename==0 ){
        //    return 0;
        //  }
        //  nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
        //  if( nByte==0 ){
        //    free(zMbcsFilename);
        //    zMbcsFileName = "";
        //  }
        //  return zMbcsFilename;
        //}

        /*
    ** Convert microsoft unicode to multibyte character string, based on the
    ** user's Ansi codepage.
    **
    ** Space to hold the returned string is obtained from
    ** malloc().
    */
        //static char *unicodeToMbcs(const WCHAR *zWideFilename){
        //  int nByte;
        //  char *zFilename;
        //  int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;

        //  nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
        //  zFilename = malloc( nByte );
        //  if( zFilename==0 ){
        //    return 0;
        //  }
        //  nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte,
        //                              0, 0);
        //  if( nByte == 0 ){
        //    free(zFilename);
        //    zFileName = "";
        //  }
        //  return zFilename;
        //}

        /*
    ** Convert multibyte character string to UTF-8.  Space to hold the
    ** returned string is obtained from malloc().
    */
        //static char *sqlite3_win32_mbcs_to_utf8(string zFilename){
        //  char *zFilenameUtf8;
        //  WCHAR *zTmpWide;

        //  zTmpWide = mbcsToUnicode(zFilename);
        //  if( zTmpWide==0 ){
        //    return 0;
        //  }
        //  zFilenameUtf8 = unicodeToUtf8(zTmpWide);
        //  free(zTmpWide);
        //  return zFilenameUtf8;
        //}

        /*
    ** Convert UTF-8 to multibyte character string.  Space to hold the
    ** returned string is obtained from malloc().
    */
        //static char *utf8ToMbcs(string zFilename){
        //  char *zFilenameMbcs;
        //  WCHAR *zTmpWide;

        //  zTmpWide = utf8ToUnicode(zFilename);
        //  if( zTmpWide==0 ){
        //    return 0;
        //  }
        //  zFilenameMbcs = unicodeToMbcs(zTmpWide);
        //  free(zTmpWide);
        //  return zFilenameMbcs;
        //}

#if SQLITE_OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
*/
/*
** WindowsCE does not have a Custom.Localtime() function.  So create a
** substitute.
*/
//#include <time.h>
struct tm *__cdecl Custom.Localtime(const time_t *t)
{
static struct tm y;
FILETIME uTm, lTm;
SYSTEMTIME pTm;
long t64;
t64 = *t;
t64 = (t64 + 11644473600)*10000000;
uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
uTm.dwHighDateTime= (DWORD)(t64 >> 32);
FileTimeToLocalFileTime(&uTm,&lTm);
FileTimeToSystemTime(&lTm,&pTm);
y.tm_year = pTm.wYear - 1900;
y.tm_mon = pTm.wMonth - 1;
y.tm_wday = pTm.wDayOfWeek;
y.tm_mday = pTm.wDay;
y.tm_hour = pTm.wHour;
y.tm_min = pTm.wMinute;
y.tm_sec = pTm.wSecond;
return &y;
}

/* This will never be called, but defined to make the code compile */
//#define GetTempPathA(a,b)

//#define LockFile(a,b,c,d,e)       winceLockFile(&a, b, c, d, e)
//#define UnlockFile(a,b,c,d,e)     winceUnlockFile(&a, b, c, d, e)
//#define LockFileEx(a,b,c,d,e,f)   winceLockFileEx(&a, b, c, d, e, f)

//#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]

/*
** Acquire a lock on the handle h
*/
static void winceMutexAcquire(HANDLE h){
DWORD dwErr;
do {
dwErr = WaitForSingleObject(h, INFINITE);
} while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
}
/*
** Release a lock acquired by winceMutexAcquire()
*/
//#define winceMutexRelease(h) ReleaseMutex(h)

/*
** Create the mutex and shared memory used for locking in the file
** descriptor pFile
*/
static BOOL winceCreateLock(string zFilename, sqlite3_file pFile){
WCHAR *zTok;
WCHAR *zName = utf8ToUnicode(zFilename);
BOOL bInit = TRUE;

/* Initialize the local lockdata */
ZeroMemory(pFile.local, pFile.local).Length;

/* Replace the backslashes from the filename and lowercase it
** to derive a mutex name. */
zTok = CharLowerW(zName);
for (;*zTok;zTok++){
if (*zTok == '\\') *zTok = '_';
}

/* Create/open the named mutex */
pFile.hMutex = CreateMutexW(NULL, FALSE, zName);
if (!pFile.hMutex){
pFile->lastErrno = (uint)GetLastError();
free(zName);
return FALSE;
}

/* Acquire the mutex before continuing */
winceMutexAcquire(pFile.hMutex);

/* Since the names of named mutexes, semaphores, file mappings etc are
** case-sensitive, take advantage of that by uppercasing the mutex name
** and using that as the shared filemapping name.
*/
CharUpperW(zName);
pFile.hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, winceLock.Length,
zName);

/* Set a flag that indicates we're the first to create the memory so it
** must be zero-initialized */
if (GetLastError() == ERROR_ALREADY_EXISTS){
bInit = FALSE;
}

free(zName);

/* If we succeeded in making the shared memory handle, map it. */
if (pFile.hShared){
pFile.shared = (winceLock*)MapViewOfFile(pFile.hShared,
FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, winceLock).Length;
/* If mapping failed, close the shared memory handle and erase it */
if (!pFile.shared){
pFile->lastErrno = (uint)GetLastError();
CloseHandle(pFile.hShared);
pFile.hShared = NULL;
}
}

/* If shared memory could not be created, then close the mutex and fail */
if (pFile.hShared == NULL){
winceMutexRelease(pFile.hMutex);
CloseHandle(pFile.hMutex);
pFile.hMutex = NULL;
return FALSE;
}

/* Initialize the shared memory if we're supposed to */
if (bInit) {
ZeroMemory(pFile.shared, winceLock).Length;
}

winceMutexRelease(pFile.hMutex);
return TRUE;
}

/*
** Destroy the part of sqlite3_file that deals with wince locks
*/
static void winceDestroyLock(sqlite3_file pFile){
if (pFile.hMutex){
/* Acquire the mutex */
winceMutexAcquire(pFile.hMutex);

/* The following blocks should probably Debug.Assert in debug mode, but they
are to cleanup in case any locks remained open */
if (pFile.local.nReaders){
pFile.shared.nReaders --;
}
if (pFile.local.bReserved){
pFile.shared.bReserved = FALSE;
}
if (pFile.local.bPending){
pFile.shared.bPending = FALSE;
}
if (pFile.local.bExclusive){
pFile.shared.bExclusive = FALSE;
}

/* De-reference and close our copy of the shared memory handle */
UnmapViewOfFile(pFile.shared);
CloseHandle(pFile.hShared);

/* Done with the mutex */
winceMutexRelease(pFile.hMutex);
CloseHandle(pFile.hMutex);
pFile.hMutex = NULL;
}
}

/*
** An implementation of the LockFile() API of windows for wince
*/
static BOOL winceLockFile(
  HANDLE *phFile,
  DWORD dwFileOffsetLow,
  DWORD dwFileOffsetHigh,
  DWORD nNumberOfBytesToLockLow,
  DWORD nNumberOfBytesToLockHigh
){
  winFile *pFile = HANDLE_TO_WINFILE(phFile);
  BOOL bReturn = FALSE;

  Helper.UNUSED_PARAMETER(dwFileOffsetHigh);
  Helper.UNUSED_PARAMETER(nNumberOfBytesToLockHigh);

  if (!pFile->hMutex) return TRUE;
  winceMutexAcquire(pFile->hMutex);

  /* Wanting an exclusive lock? */
  if (dwFileOffsetLow == (DWORD)Global.SHARED_FIRST
       && nNumberOfBytesToLockLow == (DWORD)Global.SHARED_SIZE){
    if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){
       pFile->shared->bExclusive = TRUE;
       pFile->local.bExclusive = TRUE;
       bReturn = TRUE;
    }
  }

  /* Want a read-only lock? */
  else if (dwFileOffsetLow == (DWORD)Global.SHARED_FIRST &&
           nNumberOfBytesToLockLow == 1){
    if (pFile->shared->bExclusive == 0){
      pFile->local.nReaders ++;
      if (pFile->local.nReaders == 1){
        pFile->shared->nReaders ++;
      }
      bReturn = TRUE;
    }
  }

  /* Want a pending lock? */
  else if (dwFileOffsetLow == (DWORD)Global.PENDING_BYTE && nNumberOfBytesToLockLow == 1){
    /* If no pending lock has been acquired, then acquire it */
    if (pFile->shared->bPending == 0) {
      pFile->shared->bPending = TRUE;
      pFile->local.bPending = TRUE;
      bReturn = TRUE;
    }
  }

  /* Want a reserved lock? */
  else if (dwFileOffsetLow == (DWORD)Global.RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
    if (pFile->shared->bReserved == 0) {
      pFile->shared->bReserved = TRUE;
      pFile->local.bReserved = TRUE;
      bReturn = TRUE;
    }
  }

  winceMutexRelease(pFile->hMutex);
  return bReturn;
}

/*
** An implementation of the UnlockFile API of windows for wince
*/
static BOOL winceUnlockFile(
  HANDLE *phFile,
  DWORD dwFileOffsetLow,
  DWORD dwFileOffsetHigh,
  DWORD nNumberOfBytesToUnlockLow,
  DWORD nNumberOfBytesToUnlockHigh
){
  winFile *pFile = HANDLE_TO_WINFILE(phFile);
  BOOL bReturn = FALSE;

  Helper.UNUSED_PARAMETER(dwFileOffsetHigh);
  Helper.UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);

  if (!pFile->hMutex) return TRUE;
  winceMutexAcquire(pFile->hMutex);

  /* Releasing a reader lock or an exclusive lock */
  if (dwFileOffsetLow == (DWORD)Global.SHARED_FIRST){
    /* Did we have an exclusive lock? */
    if (pFile->local.bExclusive){
      assert(nNumberOfBytesToUnlockLow == (DWORD)Global.SHARED_SIZE);
      pFile->local.bExclusive = FALSE;
      pFile->shared->bExclusive = FALSE;
      bReturn = TRUE;
    }

    /* Did we just have a reader lock? */
    else if (pFile->local.nReaders){
      assert(nNumberOfBytesToUnlockLow == (DWORD)Global.SHARED_SIZE || nNumberOfBytesToUnlockLow == 1);
      pFile->local.nReaders --;
      if (pFile->local.nReaders == 0)
      {
        pFile->shared->nReaders --;
      }
      bReturn = TRUE;
    }
  }

  /* Releasing a pending lock */
  else if (dwFileOffsetLow == (DWORD)Global.PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
    if (pFile->local.bPending){
      pFile->local.bPending = FALSE;
      pFile->shared->bPending = FALSE;
      bReturn = TRUE;
    }
  }
  /* Releasing a reserved lock */
  else if (dwFileOffsetLow == (DWORD)Global.RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
    if (pFile->local.bReserved) {
      pFile->local.bReserved = FALSE;
      pFile->shared->bReserved = FALSE;
      bReturn = TRUE;
    }
  }

  winceMutexRelease(pFile->hMutex);
  return bReturn;
}

/*
** An implementation of the LockFileEx() API of windows for wince
*/
static BOOL winceLockFileEx(
  HANDLE *phFile,
  DWORD dwFlags,
  DWORD dwReserved,
  DWORD nNumberOfBytesToLockLow,
  DWORD nNumberOfBytesToLockHigh,
  LPOVERLAPPED lpOverlapped
){
  Helper.UNUSED_PARAMETER(dwReserved);
  Helper.UNUSED_PARAMETER(nNumberOfBytesToLockHigh);

  /* If the caller wants a shared read lock, forward this call
  ** to winceLockFile */
  if (lpOverlapped->Offset == (DWORD)Global.SHARED_FIRST &&
      dwFlags == 1 &&
      nNumberOfBytesToLockLow == (DWORD)Global.SHARED_SIZE){
    return winceLockFile(phFile, Global.SHARED_FIRST, 0, 1, 0);
  }
  return FALSE;
}
/*
** End of the special code for wince
*****************************************************************************/
#endif
        // * SQLITE_OS_WINCE */

        /*****************************************************************************
** The next group of routines implement the I/O methods specified
** by the sqlite3_io_methods object.
******************************************************************************/

        /*
    ** Close a file.
    **
    ** It is reported that an attempt to close a handle might sometimes
    ** fail.  This is a very unreasonable result, but windows is notorious
    ** for being unreasonable so I do not doubt that it might happen.  If
    ** the close fails, we pause for 100 milliseconds and try again.  As
    ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
    ** giving up and returning an error.
    */
        public static int MX_CLOSE_ATTEMPT = 3;

        private static int winClose(sqlite3_file id)
        {
            bool rc;
            int cnt = 0;
            sqlite3_file pFile = id;

            Debug.Assert(id != null);
#if SQLITE_DEBUG
            OSTRACE3("CLOSE %d (%s)\n", pFile.fs.GetHashCode(), pFile.fs.Name);
#endif
            do
            {
                pFile.fs.Close();
                rc = true;
                //  rc = CloseHandle(pFile.h);
                //  if (!rc && ++cnt < MX_CLOSE_ATTEMPT) Thread.Sleep(100); //, 1) );
            } while (!rc && ++cnt < MX_CLOSE_ATTEMPT); //, 1) );
#if SQLITE_OS_WINCE
//#define WINCE_DELETION_ATTEMPTS 3
winceDestroyLock(pFile);
if( pFile.zDeleteOnClose ){
int cnt = 0;
while(
DeleteFileW(pFile.zDeleteOnClose)==0
&& GetFileAttributesW(pFile.zDeleteOnClose)!=0xffffffff
&& cnt++ < WINCE_DELETION_ATTEMPTS
){
Sleep(100);  /* Wait a little before trying again */
}
free(pFile.zDeleteOnClose);
}
#endif
#if SQLITE_TEST
      OpenCounter( -1 );
#endif
            return rc ? StatusCode.SQLITE_OK : StatusCode.SQLITE_IOERR;
        }

        /*
    ** Some microsoft compilers lack this definition.
    */
#if !INVALID_SET_FILE_POINTER
        private const int INVALID_SET_FILE_POINTER = -1;
#endif

        /*
** Read data from a file into a buffer.  Return StatusCode.SQLITE_OK if all
** bytes were read successfully and StatusCode.SQLITE_IOERR if anything goes
** wrong.
*/

        private static int winRead(
            sqlite3_file id, /* File to read from */
            byte[] pBuf, /* Write content into this buffer */
            int amt, /* Number of bytes to read */
            long offset /* Begin reading at this offset */
            )
        {
            //LONG upperBits = (LONG)( ( offset >> 32 ) & 0x7fffffff );
            //LONG lowerBits = (LONG)( offset & 0xffffffff );
            long rc;
            sqlite3_file pFile = id;
            //DWORD error;
            long got;

            Debug.Assert(id != null);
#if SQLITE_TEST
    //SimulateIOError(return ExtendedResultCode.SQLITE_IOERR_READ);  TODO --  How to implement this?
#endif
#if SQLITE_DEBUG
            OSTRACE3("READ %d lock=%d\n", pFile.fs.GetHashCode(), pFile.locktype);
#endif
            if (!id.fs.CanRead) return ExtendedResultCode.SQLITE_IOERR_READ;
            try
            {
                rc = id.fs.Seek(offset, SeekOrigin.Begin);
                    // SetFilePointer(pFile.fs.Name, lowerBits, upperBits, FILE_BEGIN);
            }
            catch (Exception e) //            if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR )
            {
#if SQLITE_SILVERLIGHT
                pFile.lastErrno = 1;
#else
                pFile.lastErrno = (uint) Marshal.GetLastWin32Error();
#endif
                return StatusCode.SQLITE_FULL;
            }

            try
            {
                got = id.fs.Read(pBuf, 0, amt); // if (!ReadFile(pFile.fs.Name, pBuf, amt, got, 0))
            }
            catch (Exception e)
            {
#if SQLITE_SILVERLIGHT
                pFile.lastErrno = 1;
#else
                pFile.lastErrno = (uint) Marshal.GetLastWin32Error();
#endif
                return ExtendedResultCode.SQLITE_IOERR_READ;
            }
            if (got == amt)
            {
                return StatusCode.SQLITE_OK;
            }
            else
            {
                /* Unread parts of the buffer must be zero-filled */
                Array.Clear(pBuf, (int) got, (int) (amt - got)); // memset(&((char*)pBuf)[got], 0, amt - got);
                return ExtendedResultCode.SQLITE_IOERR_SHORT_READ;
            }
        }

        /*
    ** Write data from a buffer into a file.  Return StatusCode.SQLITE_OK on success
    ** or some other error code on failure.
    */

        private static int winWrite(
            sqlite3_file id, /* File to write into */
            byte[] pBuf, /* The bytes to be written */
            int amt, /* Number of bytes to write */
            long offset /* Offset into the file to begin writing at */
            )
        {
            //LONG upperBits = (LONG)( ( offset >> 32 ) & 0x7fffffff );
            //LONG lowerBits = (LONG)( offset & 0xffffffff );
            int rc;
            //  sqlite3_file pFile = (sqlite3_file*)id;
            //  DWORD error;
            long wrote = 0;

            Debug.Assert(id != null);
#if SQLITE_TEST
      if ( SimulateIOError() ) return ExtendedResultCode.SQLITE_IOERR_WRITE;
      if ( SimulateDiskfullError() ) return StatusCode.SQLITE_FULL;
#endif
#if SQLITE_DEBUG
            OSTRACE3("WRITE %d lock=%d\n", id.fs.GetHashCode(), id.locktype);
#endif
            //  rc = SetFilePointer(pFile.fs.Name, lowerBits, upperBits, FILE_BEGIN);
            id.fs.Seek(offset, SeekOrigin.Begin);
            //  if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
            //  pFile.lastErrno = (uint)GetLastError();
            //    return StatusCode.SQLITE_FULL;
            //  }
            Debug.Assert(amt > 0);
            wrote = id.fs.Position;
            try
            {
                Debug.Assert(pBuf.Length >= amt);
                id.fs.Write(pBuf, 0, amt);
                rc = 1; // Success
                wrote = id.fs.Position - wrote;
            }
            catch (IOException e)
            {
                return StatusCode.SQLITE_READONLY;
            }
            //  while(
            //     amt>0
            //     && (rc = WriteFile(pFile.fs.Name, pBuf, amt, wrote, 0))!=0
            //     && wrote>0
            //  ){
            //    amt -= wrote;
            //    pBuf = &((char*)pBuf)[wrote];
            //  }
            if (rc == 0 || amt > (int) wrote)
            {
#if SQLITE_SILVERLIGHT
                id.lastErrno  = 1;
#else
                id.lastErrno = (uint) Marshal.GetLastWin32Error();
#endif
                return StatusCode.SQLITE_FULL;
            }
            return StatusCode.SQLITE_OK;
        }

        /*
    ** Truncate an open file to a specified size
    */

        private static int winTruncate(sqlite3_file id, long nByte)
        {
            //LONG upperBits = (LONG)( ( nByte >> 32 ) & 0x7fffffff );
            //LONG lowerBits = (LONG)( nByte & 0xffffffff );
            //DWORD rc;
            //winFile* pFile = (winFile*)id;
            //DWORD error;

            Debug.Assert(id != null);
#if SQLITE_DEBUG
            OSTRACE3("TRUNCATE %d %lld\n", id.fs.Name, nByte);
#endif
#if SQLITE_TEST
    //SimulateIOError(return ExtendedResultCode.SQLITE_IOERR_TRUNCATE);  TODO --  How to implement this?
#endif
            //rc = SetFilePointer( pFile->h, lowerBits, &upperBits, FILE_BEGIN );
            //if ( rc == INVALID_SET_FILE_POINTER && ( error = GetLastError() ) != NO_ERROR )
            //{
            //  pFile->lastErrno = error;
            //  return ExtendedResultCode.SQLITE_IOERR_TRUNCATE;
            //}
            ///* SetEndOfFile will fail if nByte is negative */
            //if ( !SetEndOfFile( pFile->h ) )
            //{
            //  pFile->lastErrno = GetLastError();
            //  return ExtendedResultCode.SQLITE_IOERR_TRUNCATE;
            //}
            try
            {
                id.fs.SetLength(nByte);
            }
            catch (IOException e)
            {
#if SQLITE_SILVERLIGHT
                id.lastErrno  = 1;
#else
                id.lastErrno = (uint) Marshal.GetLastWin32Error();
#endif
                return ExtendedResultCode.SQLITE_IOERR_TRUNCATE;
            }
            return StatusCode.SQLITE_OK;
        }

#if SQLITE_TEST
    /*
** Count the number of fullsyncs and normal syncs.  This is used to test
** that syncs and fullsyncs are occuring at the right times.
*/
    static int sqlite3_sync_count = 0;
    static int sqlite3_fullsync_count = 0;
#endif

        /*
** Make sure all writes to a particular file are committed to disk.
*/

        private static int winSync(sqlite3_file id, int flags)
        {
#if !SQLITE_NO_SYNC
            sqlite3_file pFile = id;
            Debug.Assert(id != null);
#if SQLITE_DEBUG
            OSTRACE3("SYNC %d lock=%d\n", pFile.fs.GetHashCode(), pFile.locktype);
#endif
#else
Helper.UNUSED_PARAMETER(id);
#endif
#if !SQLITE_TEST
            Helper.UNUSED_PARAMETER(flags);
#else
      if ( ( flags & SyncTypeFlag.SQLITE_SYNC_FULL ) != 0 )
      {
        sqlite3_fullsync_count++;
      }
      sqlite3_sync_count++;
#endif
            /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
** no-op
*/
#if SQLITE_NO_SYNC
return StatusCode.SQLITE_OK;
#else
            pFile.fs.Flush();
            return StatusCode.SQLITE_OK;
            //if (FlushFileBuffers(pFile.h) != 0)
            //{
            //  return StatusCode.SQLITE_OK;
            //}
            //else
            //{
            //  pFile->lastErrno = (uint)GetLastError();
            //  return StatusCode.SQLITE_IOERR;
            //}
#endif
        }

        /*
    ** Determine the current size of a file in bytes
    */

        private static int sqlite3_fileSize(sqlite3_file id, ref int pSize)
        {
            //DWORD upperBits;
            //DWORD lowerBits;
            //  sqlite3_file pFile = (sqlite3_file)id;
            //  DWORD error;
            Debug.Assert(id != null);
#if SQLITE_TEST
    //SimulateIOError(return ExtendedResultCode.SQLITE_IOERR_FSTAT);  TODO --  How to implement this?
#endif
            //lowerBits = GetFileSize(pFile.fs.Name, upperBits);
            //if ( ( lowerBits == INVALID_FILE_SIZE )
            //   && ( ( error = GetLastError() ) != NO_ERROR ) )
            //{
            //  pFile->lastErrno = error;
            //  return ExtendedResultCode.SQLITE_IOERR_FSTAT;
            //}
            //pSize = (((long)upperBits)<<32) + lowerBits;
            pSize = id.fs.CanRead ? (int) id.fs.Length : 0;
            return StatusCode.SQLITE_OK;
        }


        /*
    ** Acquire a reader lock.
    ** Different API routines are called depending on whether or not this
    ** is Win95 or WinNT.
    */

        private static int getReadLock(sqlite3_file pFile)
        {
            int res = 0;
            if (isNT())
            {
                res = lockingStrategy.SharedLockFile(pFile, Global.SHARED_FIRST, Global.SHARED_SIZE);
            }
            /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
      */
#if !SQLITE_OS_WINCE
            //else
            //{
            //  int lk;
            //  Random.Randomness(lk.Length, lk);
            //  pFile->sharedLockByte = (ushort)((lk & 0x7fffffff)%(Global.SHARED_SIZE - 1));
            //  res = pFile.fs.Lock( Global.SHARED_FIRST + pFile.sharedLockByte, 0, 1, 0);
#endif
            //}
            if (res == 0)
            {
#if SQLITE_SILVERLIGHT
                pFile.lastErrno = 1;
#else
                pFile.lastErrno = (uint) Marshal.GetLastWin32Error();
#endif
            }
            return res;
        }

        /*
    ** Undo a readlock
    */

        private static int unlockReadLock(sqlite3_file pFile)
        {
            int res = 1;
            if (isNT())
            {
                try
                {
                    lockingStrategy.UnlockFile(pFile, Global.SHARED_FIRST, Global.SHARED_SIZE);
                        //     res = UnlockFile(pFilE.h, Global.SHARED_FIRST, 0, Global.SHARED_SIZE, 0);
                }
                catch (Exception e)
                {
                    res = 0;
                }
            }
                /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
      */
#if !SQLITE_OS_WINCE
            else
            {
                Debugger.Break(); //    res = UnlockFile(pFilE.h, Global.SHARED_FIRST + pFilE.sharedLockByte, 0, 1, 0);
            }
#endif
            if (res == 0)
            {
#if SQLITE_SILVERLIGHT
                pFile.lastErrno = 1;
#else
                pFile.lastErrno = (uint) Marshal.GetLastWin32Error();
#endif
            }
            return res;
        }

        /*
    ** Lock the file with the lock specified by parameter locktype - one
    ** of the following:
    **
    **     (1) OsLockType.SHARED_LOCK
    **     (2) OsLockType.RESERVED_LOCK
    **     (3) OsLockType.PENDING_LOCK
    **     (4) OsLockType.EXCLUSIVE_LOCK
    **
    ** Sometimes when requesting one lock state, additional lock states
    ** are inserted in between.  The locking might fail on one of the later
    ** transitions leaving the lock state different from what it started but
    ** still short of its goal.  The following chart shows the allowed
    ** transitions and the inserted intermediate states:
    **
    **    UNLOCKED -> SHARED
    **    SHARED -> RESERVED
    **    SHARED -> (PENDING) -> EXCLUSIVE
    **    RESERVED -> (PENDING) -> EXCLUSIVE
    **    PENDING -> EXCLUSIVE
    **
    ** This routine will only increase a lock.  The winUnlock() routine
    ** erases all locks at once and returns us immediately to locking level 0.
    ** It is not possible to lower the locking level one step at a time.  You
    ** must go straight to locking level 0.
    */

        private static int winLock(sqlite3_file id, int locktype)
        {
            int rc = StatusCode.SQLITE_OK; /* Return code from subroutines */
            int res = 1; /* Result of a windows lock call */
            int newLocktype; /* Set pFile.locktype to this value before exiting */
            bool gotPendingLock = false; /* True if we acquired a PENDING lock this time */
            sqlite3_file pFile = id;
            DWORD error = NO_ERROR;

            Debug.Assert(id != null);
#if SQLITE_DEBUG
            OSTRACE5("LOCK %d %d was %d(%d)\n",
                     pFile.fs.GetHashCode(), locktype, pFile.locktype, pFile.sharedLockByte);
#endif
            /* If there is already a lock of this type or more restrictive on the
** OsFile, do nothing. Don't use the end_lock: exit path, as
** sqlite3OsEnterMutex() hasn't been called yet.
*/
            if (pFile.locktype >= locktype)
            {
                return StatusCode.SQLITE_OK;
            }

            /* Make sure the locking sequence is correct
      */
            Debug.Assert(pFile.locktype != OsLockType.NO_LOCK || locktype == OsLockType.SHARED_LOCK);
            Debug.Assert(locktype != OsLockType.PENDING_LOCK);
            Debug.Assert(locktype != OsLockType.RESERVED_LOCK || pFile.locktype == OsLockType.SHARED_LOCK);

            /* Lock the OsLockType.PENDING_LOCK byte if we need to acquire a PENDING lock or
      ** a SHARED lock.  If we are acquiring a SHARED lock, the acquisition of
      ** the OsLockType.PENDING_LOCK byte is temporary.
      */
            newLocktype = pFile.locktype;
            if (pFile.locktype == OsLockType.NO_LOCK
                || ((locktype == OsLockType.EXCLUSIVE_LOCK)
                    && (pFile.locktype == OsLockType.RESERVED_LOCK))
                )
            {
                int cnt = 3;
                res = 0;
                while (cnt-- > 0 && res == 0)
                    //(res = LockFile(pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32(), Global.PENDING_BYTE, 0, 1, 0)) == 0)
                {
                    try
                    {
                        lockingStrategy.LockFile(pFile, Global.PENDING_BYTE, 1);
                        res = 1;
                    }
                    catch (Exception e)
                    {
                        /* Try 3 times to get the pending lock.  The pending lock might be
            ** held by another reader process who will release it momentarily.
            */
#if SQLITE_DEBUG
                        OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
#endif
                        Thread.Sleep(1);
                    }
                }
                gotPendingLock = (res != 0);
                if (0 == res)
                {
#if SQLITE_SILVERLIGHT
                error = 1;
#else
                    error = (uint) Marshal.GetLastWin32Error();
#endif
                }
            }

            /* Acquire a shared lock
      */
            if (locktype == OsLockType.SHARED_LOCK && res != 0)
            {
                Debug.Assert(pFile.locktype == OsLockType.NO_LOCK);
                res = getReadLock(pFile);
                if (res != 0)
                {
                    newLocktype = OsLockType.SHARED_LOCK;
                }
                else
                {
#if SQLITE_SILVERLIGHT
                error = 1;
#else
                    error = (uint) Marshal.GetLastWin32Error();
#endif
                }
            }

            /* Acquire a RESERVED lock
      */
            if ((locktype == OsLockType.RESERVED_LOCK) && res != 0)
            {
                Debug.Assert(pFile.locktype == OsLockType.SHARED_LOCK);
                try
                {
                    lockingStrategy.LockFile(pFile, Global.RESERVED_BYTE, 1);
                        //res = LockFile(pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32(), Global.RESERVED_BYTE, 0, 1, 0);
                    newLocktype = OsLockType.RESERVED_LOCK;
                    res = 1;
                }
                catch (Exception e)
                {
                    res = 0;
#if SQLITE_SILVERLIGHT
                error = 1;
#else
                    error = (uint) Marshal.GetLastWin32Error();
#endif
                }
                if (res != 0)
                {
                    newLocktype = OsLockType.RESERVED_LOCK;
                }
                else
                {
#if SQLITE_SILVERLIGHT
                error = 1;
#else
                    error = (uint) Marshal.GetLastWin32Error();
#endif
                }
            }

            /* Acquire a PENDING lock
      */
            if (locktype == OsLockType.EXCLUSIVE_LOCK && res != 0)
            {
                newLocktype = OsLockType.PENDING_LOCK;
                gotPendingLock = false;
            }

            /* Acquire an EXCLUSIVE lock
      */
            if (locktype == OsLockType.EXCLUSIVE_LOCK && res != 0)
            {
                Debug.Assert(pFile.locktype >= OsLockType.SHARED_LOCK);
                res = unlockReadLock(pFile);
#if SQLITE_DEBUG
                OSTRACE2("unreadlock = %d\n", res);
#endif
                //res = LockFile(pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32(), Global.SHARED_FIRST, 0, Global.SHARED_SIZE, 0);
                try
                {
                    lockingStrategy.LockFile(pFile, Global.SHARED_FIRST, Global.SHARED_SIZE);
                    newLocktype = OsLockType.EXCLUSIVE_LOCK;
                    res = 1;
                }
                catch (Exception e)
                {
                    res = 0;
                }
                if (res != 0)
                {
                    newLocktype = OsLockType.EXCLUSIVE_LOCK;
                }
                else
                {
#if SQLITE_SILVERLIGHT
                error = 1;
#else
                    error = (uint) Marshal.GetLastWin32Error();
#endif
#if SQLITE_DEBUG
                    OSTRACE2("error-code = %d\n", error);
#endif
                    getReadLock(pFile);
                }
            }

            /* If we are holding a PENDING lock that ought to be released, then
      ** release it now.
      */
            if (gotPendingLock && locktype == OsLockType.SHARED_LOCK)
            {
                lockingStrategy.UnlockFile(pFile, Global.PENDING_BYTE, 1);
            }

            /* Update the state of the lock has held in the file descriptor then
      ** return the appropriate result code.
      */
            if (res != 0)
            {
                rc = StatusCode.SQLITE_OK;
            }
            else
            {
#if SQLITE_DEBUG
                OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile.fs.GetHashCode(),
                         locktype, newLocktype);
#endif
                pFile.lastErrno = error;
                rc = StatusCode.SQLITE_BUSY;
            }
            pFile.locktype = (byte) newLocktype;
            return rc;
        }

        /*
    ** This routine checks if there is a RESERVED lock held on the specified
    ** file by this or any other process. If such a lock is held, return
    ** non-zero, otherwise zero.
    */

        private static int winCheckReservedLock(sqlite3_file id, ref int pResOut)
        {
            int rc;
            sqlite3_file pFile = id;
            Debug.Assert(id != null);
            if (pFile.locktype >= OsLockType.RESERVED_LOCK)
            {
                rc = 1;
#if SQLITE_DEBUG
                OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile.fs.Name, rc);
#endif
            }
            else
            {
                try
                {
                    lockingStrategy.LockFile(pFile, Global.RESERVED_BYTE, 1);
                    lockingStrategy.UnlockFile(pFile, Global.RESERVED_BYTE, 1);
                    rc = 1;
                }
                catch (IOException e)
                {
                    rc = 0;
                }
                rc = 1 - rc; // !rc
#if SQLITE_DEBUG
                OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile.fs.GetHashCode(), rc);
#endif
            }
            pResOut = rc;
            return StatusCode.SQLITE_OK;
        }

        /*
    ** Lower the locking level on file descriptor id to locktype.  locktype
    ** must be either OsLockType.NO_LOCK or OsLockType.SHARED_LOCK.
    **
    ** If the locking level of the file descriptor is already at or below
    ** the requested locking level, this routine is a no-op.
    **
    ** It is not possible for this routine to fail if the second argument
    ** is OsLockType.NO_LOCK.  If the second argument is OsLockType.SHARED_LOCK then this routine
    ** might return StatusCode.SQLITE_IOERR;
    */

        private static int winUnlock(sqlite3_file id, int locktype)
        {
            int type;
            sqlite3_file pFile = id;
            int rc = StatusCode.SQLITE_OK;
            Debug.Assert(pFile != null);
            Debug.Assert(locktype <= OsLockType.SHARED_LOCK);

#if SQLITE_DEBUG
            OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile.fs.GetHashCode(), locktype,
                     pFile.locktype, pFile.sharedLockByte);
#endif
            type = pFile.locktype;
            if (type >= OsLockType.EXCLUSIVE_LOCK)
            {
                lockingStrategy.UnlockFile(pFile, Global.SHARED_FIRST, Global.SHARED_SIZE);
                    // UnlockFile(pFilE.h, Global.SHARED_FIRST, 0, Global.SHARED_SIZE, 0);
                if (locktype == OsLockType.SHARED_LOCK && getReadLock(pFile) == 0)
                {
                    /* This should never happen.  We should always be able to
          ** reacquire the read lock */
                    rc = ExtendedResultCode.SQLITE_IOERR_UNLOCK;
                }
            }
            if (type >= OsLockType.RESERVED_LOCK)
            {
                try
                {
                    lockingStrategy.UnlockFile(pFile, Global.RESERVED_BYTE, 1); // UnlockFile(pFilE.h, Global.RESERVED_BYTE, 0, 1, 0);
                }
                catch (Exception e)
                {
                }
            }
            if (locktype == OsLockType.NO_LOCK && type >= OsLockType.SHARED_LOCK)
            {
                unlockReadLock(pFile);
            }
            if (type >= OsLockType.PENDING_LOCK)
            {
                try
                {
                    lockingStrategy.UnlockFile(pFile, Global.PENDING_BYTE, 1);
                        //    UnlockFile(pFilE.h, Global.PENDING_BYTE, 0, 1, 0);
                }
                catch (Exception e)
                {
                }
            }
            pFile.locktype = (byte) locktype;
            return rc;
        }

        /*
    ** Control and query of the open file handle.
    */

        private static int winFileControl(sqlite3_file id, int op, ref int pArg)
        {
            switch (op)
            {
                case SQLITE_FCNTL_LOCKSTATE:
                    {
                        pArg = (id).locktype;
                        return StatusCode.SQLITE_OK;
                    }
                case SQLITE_LAST_ERRNO:
                    {
                        pArg = (int) (id).lastErrno;
                        return StatusCode.SQLITE_OK;
                    }
            }
            return StatusCode.SQLITE_ERROR;
        }

        /*
    ** Return the sector size in bytes of the underlying block device for
    ** the specified file. This is almost always 512 bytes, but may be
    ** larger for some devices.
    **
    ** SQLite code assumes this function cannot fail. It also assumes that
    ** if two files are created in the same file-system directory (i.e.
    ** a database and its journal file) that the sector size will be the
    ** same for both.
    */

        private static int winSectorSize(sqlite3_file id)
        {
            Debug.Assert(id != null);
            return (int) (id.sectorSize);
        }

        /*
    ** Return a vector of device characteristics.
    */

        private static int winDeviceCharacteristics(sqlite3_file id)
        {
            Helper.UNUSED_PARAMETER(id);
            return 0;
        }

        /*
    ** This vector defines all the methods that can operate on an
    ** sqlite3_file for win32.
    */

        private static readonly sqlite3_io_methods winIoMethod = new sqlite3_io_methods(
            1, /* iVersion */
            winClose,
            winRead,
            winWrite,
            winTruncate,
            winSync,
            sqlite3_fileSize,
            winLock,
            winUnlock,
            winCheckReservedLock,
            winFileControl,
            winSectorSize,
            winDeviceCharacteristics
            );

        /***************************************************************************
    ** Here ends the I/O methods that form the sqlite3_io_methods object.
    **
    ** The next block of code implements the VFS methods.
    ****************************************************************************/

        /*
    ** Convert a UTF-8 filename into whatever form the underlying
    ** operating system wants filenames in.  Space to hold the result
    ** is obtained from malloc and must be freed by the calling
    ** function.
    */

        private static string convertUtf8Filename(string zFilename)
        {
            return zFilename;
            // string zConverted = "";
            //if (isNT())
            //{
            //  zConverted = utf8ToUnicode(zFilename);
            /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
      */
#if !SQLITE_OS_WINCE
            //}
            //else
            //{
            //  zConverted = utf8ToMbcs(zFilename);
#endif
            //}
            /* caller will handle out of memory */
            //return zConverted;
        }

        /*
    ** Create a temporary file name in zBuf.  zBuf must be big enough to
    ** hold at pVfs.mxPathname characters.
    */

        private static int getTempname(int nBuf, StringBuilder zBuf)
        {
            const string zChars = "abcdefghijklmnopqrstuvwxyz0123456789";
            //static char zChars[] =
            //  "abcdefghijklmnopqrstuvwxyz"
            //  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            //  "0123456789";
            //size_t i, j;
            //char zTempPath[MAX_PATH+1];
            //if( sqlite3_temp_directory ){
            //  Print.Snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
            //}else if( isNT() ){
            //  char *zMulti;
            //  WCHAR zWidePath[MAX_PATH];
            //  GetTempPathW(MAX_PATH-30, zWidePath);
            //  zMulti = unicodeToUtf8(zWidePath);
            //  if( zMulti ){
            //    Print.Snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
            //    free(zMulti);
            //  }else{
            //    return StatusCode.SQLITE_NOMEM;
            //  }
            /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
      ** Since the ASCII version of these Windows API do not exist for WINCE,
      ** it's important to not reference them for WINCE builds.
      */
#if !SQLITE_OS_WINCE
            //}else{
            //  char *zUtf8;
            //  char zMbcsPath[MAX_PATH];
            //  GetTempPathA(MAX_PATH-30, zMbcsPath);
            //  zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
            //  if( zUtf8 ){
            //    Print.Snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
            //    free(zUtf8);
            //  }else{
            //    return StatusCode.SQLITE_NOMEM;
            //  }
#endif
            //}

            var zRandom = new StringBuilder(20);
            long iRandom = 0;
            for (int i = 0; i < 20; i++)
            {
                Random.Randomness(1, ref iRandom);
                zRandom.Append(zChars[(int) (iRandom%(zChars.Length - 1))]);
            }
            //  zBuf[j] = 0;
            zBuf.Append(Path.GetTempPath() + SQLITE_TEMP_FILE_PREFIX + zRandom);
            //for(i=Utility.Sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
            //zTempPath[i] = 0;
            //Print.Snprintf(nBuf-30, zBuf,
            //                 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
            //j = Utility.Sqlite3Strlen30(zBuf);
            //Random.Randomness(20, zBuf[j]);
            //for(i=0; i<20; i++, j++){
            //  zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
            //}
            //zBuf[j] = 0;

#if SQLITE_DEBUG
            OSTRACE2("TEMP FILENAME: %s\n", zBuf.ToString());
#endif
            return StatusCode.SQLITE_OK;
        }

        /*
    ** The return value of getLastErrorMsg
    ** is zero if the error message fits in the buffer, or non-zero
    ** otherwise (if the message was truncated).
    */

        private static int getLastErrorMsg(int nBuf, ref string zBuf)
        {
            /* FormatMessage returns 0 on failure.  Otherwise it
      ** returns the number of TCHARs written to the output
      ** buffer, excluding the terminating null char.
      */
            //  DWORD error = GetLastError();
            //  DWORD dwLen = 0;
            //  char *zOut = 0;

            //  if( isNT() ){
            //    WCHAR *zTempWide = NULL;
            //    dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            //                           NULL,
            //                           error,
            //                           0,
            //                           (LPWSTR) &zTempWide,
            //                           0,
            //                           0);
            //    if( dwLen > 0 ){
            //      /* allocate a buffer and convert to UTF8 */
            //      zOut = unicodeToUtf8(zTempWide);
            //      /* free the system buffer allocated by FormatMessage */
            //      LocalFree(zTempWide);
            //    }
            ///* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
            //** Since the ASCII version of these Windows API do not exist for WINCE,
            //** it's important to not reference them for WINCE builds.
            //*/
            //#if SQLITE_OS_WINCE==0
            //  }else{
            //    char *zTemp = NULL;
            //    dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            //                           NULL,
            //                           error,
            //                           0,
            //                           (LPSTR) &zTemp,
            //                           0,
            //                           0);
            //    if( dwLen > 0 ){
            //      /* allocate a buffer and convert to UTF8 */
            //      zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
            //      /* free the system buffer allocated by FormatMessage */
            //      LocalFree(zTemp);
            //    }
            //#endif
            //  }
            //  if( 0 == dwLen ){
            //    Print.Snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
            //  }else{
            //    /* copy a maximum of nBuf chars to output buffer */
            //    Print.Snprintf(nBuf, zBuf, "%s", zOut);
            //    /* free the UTF8 buffer */
            //    free(zOut);
            //  }
#if SQLITE_SILVERLIGHT
        zBuf = "Unknown error";
        return 0;
#else
            zBuf = Marshal.GetLastWin32Error().ToString(); //new Win32Exception( Marshal.GetLastWin32Error() ).Message;
#endif
            return 0;
        }

        /*
    ** Open a file.
    */

        private static int winOpen(
            sqlite3_vfs pVfs, /* Not used */
            string zName, /* Name of the file (UTF-8) */
            sqlite3_file pFile, /* Write the SQLite file handle here */
            int flags, /* Open mode flags */
            ref int pOutFlags /* Status return flags */
            )
        {
            //HANDLE h;
            FileStream fs = null;
            FileAccess dwDesiredAccess;
            FileShare dwShareMode;
            FileMode dwCreationDisposition;
#if !SQLITE_SILVERLIGHT
            FileOptions dwFlagsAndAttributes;
#endif
#if SQLITE_OS_WINCE
int isTemp = 0;
#endif
            //winFile* pFile = (winFile*)id;
            string zConverted; /* Filename in OS encoding */
            string zUtf8Name = zName; /* Filename in UTF-8 encoding */
            var zTmpname = new StringBuilder(MAX_PATH + 1); /* Buffer used to create temp filename */

            Debug.Assert(pFile != null);
            Helper.UNUSED_PARAMETER(pVfs);

            /* If the second argument to this function is NULL, generate a
      ** temporary file name to use
      */
            if (String.IsNullOrEmpty(zUtf8Name))
            {
                int rc = getTempname(MAX_PATH + 1, zTmpname);
                if (rc != StatusCode.SQLITE_OK)
                {
                    return rc;
                }
                zUtf8Name = zTmpname.ToString();
            }

            // /* Convert the filename to the system encoding. */
            zConverted = zUtf8Name; // convertUtf8Filename( zUtf8Name );
            if (String.IsNullOrEmpty(zConverted))
            {
                return StatusCode.SQLITE_NOMEM;
            }

            if ((flags & FileOpenOperation.SQLITE_OPEN_READWRITE) != 0)
            {
                dwDesiredAccess = FileAccess.Read | FileAccess.Write; // GENERIC_READ | GENERIC_WRITE;
            }
            else
            {
                dwDesiredAccess = FileAccess.Read; // GENERIC_READ;
            }
            /* FileOpenOperation.SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
      ** created. SQLite doesn't use it to indicate "exclusive access"
      ** as it is usually understood.
      */
            Debug.Assert(0 == (flags & FileOpenOperation.SQLITE_OPEN_EXCLUSIVE) || (flags & FileOpenOperation.SQLITE_OPEN_CREATE) != 0);
            if ((flags & FileOpenOperation.SQLITE_OPEN_EXCLUSIVE) != 0)
            {
                /* Creates a new file, only if it does not already exist. */
                /* If the file exists, it fails. */
                dwCreationDisposition = FileMode.CreateNew; // CREATE_NEW;
            }
            else if ((flags & FileOpenOperation.SQLITE_OPEN_CREATE) != 0)
            {
                /* Open existing file, or create if it doesn't exist */
                dwCreationDisposition = FileMode.OpenOrCreate; // OPEN_ALWAYS;
            }
            else
            {
                /* Opens a file, only if it exists. */
                dwCreationDisposition = FileMode.Open; //OPEN_EXISTING;
            }
            dwShareMode = FileShare.Read | FileShare.Write; // FILE_SHARE_READ | FILE_SHARE_WRITE;
            if ((flags & FileOpenOperation.SQLITE_OPEN_DELETEONCLOSE) != 0)
            {
#if SQLITE_OS_WINCE
dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
isTemp = 1;
#else
#if !SQLITE_SILVERLIGHT
                dwFlagsAndAttributes = FileOptions.DeleteOnClose; // FILE_ATTRIBUTE_TEMPORARY
                //| FILE_ATTRIBUTE_HIDDEN
                //| FILE_FLAG_DELETE_ON_CLOSE;
#endif
#endif
            }
            else
            {
#if !SQLITE_SILVERLIGHT
                dwFlagsAndAttributes = FileOptions.None; // FILE_ATTRIBUTE_NORMAL;
#endif
            }
            /* Reports from the internet are that performance is always
      ** better if FILE_FLAG_RANDOM_ACCESS is used.  Ticket #2699. */
#if SQLITE_OS_WINCE
dwFlagsAndAttributes |= FileOptions.RandomAccess; // FILE_FLAG_RANDOM_ACCESS;
#endif
            if (isNT())
            {
                //h = CreateFileW((WCHAR*)zConverted,
                //   dwDesiredAccess,
                //   dwShareMode,
                //   NULL,
                //   dwCreationDisposition,
                //   dwFlagsAndAttributes,
                //   NULL
                //);

                //
                // retry opening the file a few times; this is because of a racing condition between a delete and open call to the FS
                //
                int retries = 3;
                while ((fs == null) && (retries > 0))
                    try
                    {
                        retries--;
#if !SQLITE_SILVERLIGHT
                        fs = new FileStream(zConverted, dwCreationDisposition, dwDesiredAccess, dwShareMode, 4096,
                                            dwFlagsAndAttributes);
#else
            fs = new FileStream(zConverted, dwCreationDisposition, dwDesiredAccess, dwShareMode, 4096);
#endif
#if SQLITE_DEBUG
                        OSTRACE3("OPEN %d (%s)\n", fs.GetHashCode(), fs.Name);
#endif
                    }
                    catch (Exception e)
                    {
                        Thread.Sleep(100);
                    }

                /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
        ** Since the ASCII version of these Windows API do not exist for WINCE,
        ** it's important to not reference them for WINCE builds.
        */
#if !SQLITE_OS_WINCE
            }
            else
            {
                Debugger.Break(); // Not NT
                //h = CreateFileA((char*)zConverted,
                //   dwDesiredAccess,
                //   dwShareMode,
                //   NULL,
                //   dwCreationDisposition,
                //   dwFlagsAndAttributes,
                //   NULL
                //);
#endif
            }
            if (fs == null
                ||
#if !SQLITE_SILVERLIGHT
                fs.SafeFileHandle.IsInvalid 
#else
          !fs.CanRead
#endif
                ) //(h == INVALID_HANDLE_VALUE)
            {
                //        free(zConverted);
                if ((flags & FileOpenOperation.SQLITE_OPEN_READWRITE) != 0)
                {
                    return winOpen(pVfs, zName, pFile,
                                   ((flags | FileOpenOperation.SQLITE_OPEN_READONLY) & ~FileOpenOperation.SQLITE_OPEN_READWRITE), ref pOutFlags);
                }
                else
                {
                    return UnitTest.SQLITE_CANTOPEN_BKPT();
                }
            }
            //if ( pOutFlags )
            //{
            if ((flags & FileOpenOperation.SQLITE_OPEN_READWRITE) != 0)
            {
                pOutFlags = FileOpenOperation.SQLITE_OPEN_READWRITE;
            }
            else
            {
                pOutFlags = FileOpenOperation.SQLITE_OPEN_READONLY;
            }
            //}
            pFile.Clear(); // memset(pFile, 0, sizeof(*pFile));
            pFile.pMethods = winIoMethod;
            pFile.fs = fs;
            pFile.lastErrno = NO_ERROR;
            pFile.sectorSize = (ulong) getSectorSize(pVfs, zUtf8Name);
#if SQLITE_OS_WINCE
if( (flags & (FileOpenOperation.SQLITE_OPEN_READWRITE|FileOpenOperation.SQLITE_OPEN_MAIN_DB)) ==
(FileOpenOperation.SQLITE_OPEN_READWRITE|FileOpenOperation.SQLITE_OPEN_MAIN_DB)
&& !winceCreateLock(zName, pFile)
){
CloseHandle(h);
free(zConverted);
return UnitTest.SQLITE_CANTOPEN_BKPT;
}
if( isTemp ){
pFile.zDeleteOnClose = zConverted;
}else
#endif
            {
                // free(zConverted);
            }
#if SQLITE_TEST
      OpenCounter( +1 );
#endif
            return StatusCode.SQLITE_OK;
        }

        /*
    ** Delete the named file.
    **
    ** Note that windows does not allow a file to be deleted if some other
    ** process has it open.  Sometimes a virus scanner or indexing program
    ** will open a journal file shortly after it is created in order to do
    ** whatever it does.  While this other process is holding the
    ** file open, we will be unable to delete it.  To work around this
    ** problem, we delay 100 milliseconds and try to delete again.  Up
    ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
    ** up and returning an error.
    */
        private static int MX_DELETION_ATTEMPTS = 5;

        private static int winDelete(
            sqlite3_vfs pVfs, /* Not used on win32 */
            string zFilename, /* Name of file to delete */
            int syncDir /* Not used on win32 */
            )
        {
            int cnt = 0;
            int rc;
            int error;
            Helper.UNUSED_PARAMETER(pVfs);
            Helper.UNUSED_PARAMETER(syncDir);
            string zConverted = convertUtf8Filename(zFilename);
            if (zConverted == null || zConverted == "")
            {
                return StatusCode.SQLITE_NOMEM;
            }
#if SQLITE_TEST
    //SimulateIOError(return ExtendedResultCode.SQLITE_IOERR_DELETE);  TODO --  How to implement this?
#endif
            if (isNT())
            {
                do
                    //  DeleteFileW(zConverted);
                    //}while(   (   ((rc = GetFileAttributesW(zConverted)) != INVALID_FILE_ATTRIBUTES)
                    //           || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
                    //       && (++cnt < MX_DELETION_ATTEMPTS)
                    //       && (Sleep(100), 1) );
                {
                    if (!File.Exists(zFilename))
                    {
                        rc = StatusCode.SQLITE_IOERR;
                        break;
                    }
                    try
                    {
                        File.Delete(zConverted);
                        rc = StatusCode.SQLITE_OK;
                    }
                    catch (IOException e)
                    {
                        rc = StatusCode.SQLITE_IOERR;
                        Thread.Sleep(100);
                    }
                } while (rc != StatusCode.SQLITE_OK && ++cnt < MX_DELETION_ATTEMPTS);
                /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
        ** Since the ASCII version of these Windows API do not exist for WINCE,
        ** it's important to not reference them for WINCE builds.
        */
#if !SQLITE_OS_WINCE
            }
            else
            {
                do
                {
                    //DeleteFileA( zConverted );
                    //}while(   (   ((rc = GetFileAttributesA(zConverted)) != INVALID_FILE_ATTRIBUTES)
                    //           || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
                    //       && (cnt++ < MX_DELETION_ATTEMPTS)
                    //       && (Sleep(100), 1) );
                    if (!File.Exists(zFilename))
                    {
                        rc = StatusCode.SQLITE_IOERR;
                        break;
                    }
                    try
                    {
                        File.Delete(zConverted);
                        rc = StatusCode.SQLITE_OK;
                    }
                    catch (IOException e)
                    {
                        rc = StatusCode.SQLITE_IOERR;
                        Thread.Sleep(100);
                    }
                } while (rc != StatusCode.SQLITE_OK && cnt++ < MX_DELETION_ATTEMPTS);
#endif
            }
            //free(zConverted);
#if SQLITE_DEBUG
            OSTRACE2("DELETE \"%s\"\n", zFilename);
#endif
            //return ( ( rc == INVALID_FILE_ATTRIBUTES )
            //&& ( error == ERROR_FILE_NOT_FOUND ) ) ? StatusCode.SQLITE_OK : ExtendedResultCode.SQLITE_IOERR_DELETE;
            return rc;
        }

        /*
    ** Check the existence and status of a file.
    */

        private static int winAccess(
            sqlite3_vfs pVfs, /* Not used on win32 */
            string zFilename, /* Name of file to check */
            int flags, /* Type of test to make on this file */
            ref int pResOut /* OUT: Result */
            )
        {
            FileAttributes attr = 0; // DWORD attr;
            int rc = 0;
            //  void *zConverted = convertUtf8Filename(zFilename);
            Helper.UNUSED_PARAMETER(pVfs);
            //  if( zConverted==0 ){
            //    return StatusCode.SQLITE_NOMEM;
            //  }
            //if ( isNT() )
            //{
            //
            // Do a quick test to prevent the try/catch block
            if (flags == AccessFlag.SQLITE_ACCESS_EXISTS)
            {
                pResOut = File.Exists(zFilename) ? 1 : 0;
                return StatusCode.SQLITE_OK;
            }
            //
            try
            {
                attr = File.GetAttributes(zFilename); // GetFileAttributesW( (WCHAR*)zConverted );
                if (attr == FileAttributes.Directory)
                {
                    try
                    {
                        string name = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
                        FileStream fs = File.Create(name);
                        fs.Close();
                        File.Delete(name);
                        attr = FileAttributes.Normal;
                    }
                    catch (IOException e)
                    {
                        attr = FileAttributes.ReadOnly;
                    }
                }
            }
                /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
      ** Since the ASCII version of these Windows API do not exist for WINCE,
      ** it's important to not reference them for WINCE builds.
      */
#if !SQLITE_OS_WINCE
                //}
                //else
                //{
                //  attr = GetFileAttributesA( (char*)zConverted );
#endif
                //}
            catch (IOException e)
            {
            }
            //  free(zConverted);
            switch (flags)
            {
                case AccessFlag.SQLITE_ACCESS_READ:
                case AccessFlag.SQLITE_ACCESS_EXISTS:
                    rc = attr != 0 ? 1 : 0; // != INVALID_FILE_ATTRIBUTES;
                    break;
                case AccessFlag.SQLITE_ACCESS_READWRITE:
                    rc = attr == 0 ? 0 : (int) (attr & FileAttributes.ReadOnly) != 0 ? 0 : 1;
                        //FILE_ATTRIBUTE_READONLY ) == 0;
                    break;
                default:
                    Debug.Assert("" == "Invalid flags argument");
                    rc = 0;
                    break;
            }
            pResOut = rc;
            return StatusCode.SQLITE_OK;
        }

        /*
    ** Turn a relative pathname into a full pathname.  Write the full
    ** pathname into zOut[].  zOut[] will be at least pVfs.mxPathname
    ** bytes in size.
    */

        private static int winFullPathname(
            sqlite3_vfs pVfs, /* Pointer to vfs object */
            string zRelative, /* Possibly relative input path */
            int nFull, /* Size of output buffer in bytes */
            StringBuilder zFull /* Output buffer */
            )
        {
#if __CYGWIN__
Helper.UNUSED_PARAMETER(nFull);
cygwin_conv_to_full_win32_path(zRelative, zFull);
return StatusCode.SQLITE_OK;
#endif

#if SQLITE_OS_WINCE
Helper.UNUSED_PARAMETER(nFull);
/* WinCE has no concept of a relative pathname, or so I am told. */
Print.Snprintf(pVfs.mxPathname, zFull, "%s", zRelative);
return StatusCode.SQLITE_OK;
#endif

#if !SQLITE_OS_WINCE && !__CYGWIN__
            int nByte;
            //string  zConverted;
            string zOut = null;
            Helper.UNUSED_PARAMETER(nFull);
            //convertUtf8Filename(zRelative));
            if (isNT())
            {
                //string zTemp;
                //nByte = GetFullPathNameW( zConverted, 0, 0, 0) + 3;
                //zTemp = malloc( nByte*sizeof(zTemp[0]) );
                //if( zTemp==0 ){
                //  free(zConverted);
                //  return StatusCode.SQLITE_NOMEM;
                //}
                //zTemp = GetFullPathNameW(zConverted, nByte, zTemp, 0);
                // will happen on exit; was   free(zConverted);
                try
                {
                    zOut = Path.GetFullPath(zRelative); // was unicodeToUtf8(zTemp);
                }
                catch (IOException e)
                {
                    zOut = zRelative;
                }
                // will happen on exit; was   free(zTemp);
                /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
        ** Since the ASCII version of these Windows API do not exist for WINCE,
        ** it's important to not reference them for WINCE builds.
        */
#if !SQLITE_OS_WINCE
            }
            else
            {
                Debugger.Break(); // -- Not Running under NT
                //string zTemp;
                //nByte = GetFullPathNameA(zConverted, 0, 0, 0) + 3;
                //zTemp = malloc( nByte*sizeof(zTemp[0]) );
                //if( zTemp==0 ){
                //  free(zConverted);
                //  return StatusCode.SQLITE_NOMEM;
                //}
                //GetFullPathNameA( zConverted, nByte, zTemp, 0);
                // free(zConverted);
                //zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
                // free(zTemp);
#endif
            }
            if (zOut != null)
            {
                // Print.Snprintf(pVfs.mxPathname, zFull, "%s", zOut);
                if (zFull.Length > pVfs.mxPathname) zFull.Length = pVfs.mxPathname;
                zFull.Append(zOut);

                // will happen on exit; was   free(zOut);
                return StatusCode.SQLITE_OK;
            }
            else
            {
                return StatusCode.SQLITE_NOMEM;
            }
#endif
        }


        /*
    ** Get the sector size of the device used to store
    ** file.
    */

        private static int getSectorSize(
            sqlite3_vfs pVfs,
            string zRelative /* UTF-8 file name */
            )
        {
#if FALSE
      int bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
  /* GetDiskFreeSpace is not supported under WINCE */
#if SQLITE_OS_WINCE
  Helper.UNUSED_PARAMETER(pVfs);
  Helper.UNUSED_PARAMETER(zRelative);
#else
      StringBuilder zFullpath = new StringBuilder( MAX_PATH + 1 );
      int rc;
      //bool dwRet = false;
      //int dwDummy = 0;

      /*
      ** We need to get the full path name of the file
      ** to get the drive letter to look up the sector
      ** size.
      */
      rc = winFullPathname( pVfs, zRelative, MAX_PATH, zFullpath );
      if ( rc == StatusCode.SQLITE_OK )
      {
        StringBuilder zConverted = new StringBuilder( convertUtf8Filename( zFullpath.ToString() ) );
        if ( zConverted.Length != 0 )
        {
          if ( isNT() )
          {
            /* trim path to just drive reference */
            //for ( ; *p ; p++ )
            //{
            //  if ( *p == '\\' )
            //  {
            //    *p = '\0';
            //    break;
            //  }
            //}
            int i;
            for ( i = 0 ; i < zConverted.Length && i < MAX_PATH ; i++ )
            {
              if ( zConverted[i] == '\\' )
              {
                i++;
                break;
              }
            }
            zConverted.Length = i;
            //dwRet = GetDiskFreeSpace( zConverted,
            //     ref dwDummy,
            //     ref bytesPerSector,
            //     ref dwDummy,
            //     ref dwDummy );
            //}else{
            //  /* trim path to just drive reference */
            //   char *p = (char *)zConverted;
            //  for ( ; *p ; p++ )
            //  {
            //    if ( *p == '\\' )
            //    {
            //      *p = '\0';
            //      break;
            //    }
            //  }
            //        dwRet = GetDiskFreeSpaceA((char*)zConverted,
            //                                  dwDummy,
            //                                  ref bytesPerSector,
            //                                  dwDummy,
            //                                  dwDummy );
          }
          //free(zConverted);
        }
        //  if ( !dwRet )
        //  {
        //    bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
        //  }
        //}
        //#endif
        bytesPerSector = GetbytesPerSector( zConverted );
      }
#endif
      return bytesPerSector == 0 ? SQLITE_DEFAULT_SECTOR_SIZE : bytesPerSector;
#endif
            return SQLITE_DEFAULT_SECTOR_SIZE;
        }

#if !SQLITE_OMIT_LOAD_EXTENSION
        /*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
        /*
    ** Interfaces for opening a shared library, finding entry points
    ** within the shared library, and closing the shared library.
    */
        //static void *winDlOpen(sqlite3_vfs pVfs, string zFilename){
        //  HANDLE h;
        //  void *zConverted = convertUtf8Filename(zFilename);
        //  Helper.UNUSED_PARAMETER(pVfs);
        //  if( zConverted==0 ){
        //    return 0;
        //  }
        //  if( isNT() ){
        //    h = LoadLibraryW((WCHAR*)zConverted);
        /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
    ** Since the ASCII version of these Windows API do not exist for WINCE,
    ** it's important to not reference them for WINCE builds.
    */
#if !SQLITE_OS_WINCE
        //  }else{
        //    h = LoadLibraryA((char*)zConverted);
#endif
        //  }
        //  free(zConverted);
        //  return (void*)h;
        //}
        //static void winDlError(sqlite3_vfs pVfs, int nBuf, char *zBufOut){
        //  Helper.UNUSED_PARAMETER(pVfs);
        //  getLastErrorMsg(nBuf, zBufOut);
        //}
        //    static object winDlSym(sqlite3_vfs pVfs, HANDLE pHandle, String zSymbol){
        //  Helper.UNUSED_PARAMETER(pVfs);
        //#if SQLITE_OS_WINCE
        //      /* The GetProcAddressA() routine is only available on wince. */
        //      return GetProcAddressA((HANDLE)pHandle, zSymbol);
        //#else
        //     /* All other windows platforms expect GetProcAddress() to take
        //      ** an Ansi string regardless of the _UNICODE setting */
        //      return GetProcAddress((HANDLE)pHandle, zSymbol);
        //#endif
        //   }
        //    static void winDlClose( sqlite3_vfs pVfs, HANDLE pHandle )
        //   {
        //  Helper.UNUSED_PARAMETER(pVfs);
        //     FreeLibrary((HANDLE)pHandle);
        //   }
        //TODO -- Fix This
        private static HANDLE winDlOpen(sqlite3_vfs vfs, string zFilename)
        {
            return new HANDLE();
        }

        private static int winDlError(sqlite3_vfs vfs, int nByte, ref string zErrMsg)
        {
            return 0;
        }

        private static HANDLE winDlSym(sqlite3_vfs vfs, HANDLE data, string zSymbol)
        {
            return new HANDLE();
        }

        private static int winDlClose(sqlite3_vfs vfs, HANDLE data)
        {
            return 0;
        }
#else // * if SQLITE_OMIT_LOAD_EXTENSION is defined: */
static object winDlOpen(ref sqlite3_vfs vfs, string zFilename) { return null; }
static int winDlError(ref sqlite3_vfs vfs, int nByte, ref string zErrMsg) { return 0; }
static object winDlSym(ref sqlite3_vfs vfs, object data, string zSymbol) { return null; }
static int winDlClose(ref sqlite3_vfs vfs, object data) { return 0; }
#endif


        /*
** Write up to nBuf bytes of randomness into zBuf.
*/

        //[StructLayout( LayoutKind.Explicit, Size = 16, CharSet = CharSet.Ansi )]
        //public class _SYSTEMTIME
        //{
        //  [FieldOffset( 0 )]
        //  public uint byte_0_3;
        //  [FieldOffset( 4 )]
        //  public uint byte_4_7;
        //  [FieldOffset( 8 )]
        //  public uint byte_8_11;
        //  [FieldOffset( 12 )]
        //  public uint byte_12_15;
        //}
        //[DllImport( "Kernel32.dll" )]
        //private static extern bool QueryPerformanceCounter( out long lpPerformanceCount );

        private static int winRandomness(sqlite3_vfs pVfs, int nBuf, ref byte[] zBuf)
        {
            int n = 0;
            Helper.UNUSED_PARAMETER(pVfs);
#if (SQLITE_TEST)
      n = nBuf;
      Array.Clear( zBuf, 0, n );// memset( zBuf, 0, nBuf );
#else
            byte[] sBuf = BitConverter.GetBytes(DateTime.Now.Ticks);
            zBuf[0] = sBuf[0];
            zBuf[1] = sBuf[1];
            zBuf[2] = sBuf[2];
            zBuf[3] = sBuf[3];
            ; // memcpy(&zBuf[n], x, sizeof(x))
            n += 16; // sizeof(x);
            if (sizeof (DWORD) <= nBuf - n)
            {
//DWORD pid = GetCurrentProcessId();
                uint processId;
#if !SQLITE_SILVERLIGHT
                processId = (uint) Process.GetCurrentProcess().Id;
#else
    processId = 28376023;
#endif
                put32bits(zBuf, n, processId); //(memcpy(&zBuf[n], pid, sizeof(pid));
                n += 4; // sizeof(pid);
            }
            if (sizeof (DWORD) <= nBuf - n)
            {
//DWORD cnt = GetTickCount();
                var dt = new DateTime();
                put32bits(zBuf, n, (uint) dt.Ticks); // memcpy(&zBuf[n], cnt, sizeof(cnt));
                n += 4; // cnt.Length;
            }
            if (sizeof (long) <= nBuf - n)
            {
                long i;
                i = DateTime.UtcNow.Millisecond; // QueryPerformanceCounter(out i);
                put32bits(zBuf, n, (uint) (i & 0xFFFFFFFF)); //memcpy(&zBuf[n], i, sizeof(i));
                put32bits(zBuf, n, (uint) (i >> 32));
                n += sizeof (long);
            }
#endif
            return n;
        }


        /*
    ** Sleep for a little while.  Return the amount of time slept.
    */

        private static int winSleep(sqlite3_vfs pVfs, int microsec)
        {
            Thread.Sleep((microsec + 999)/1000);
            Helper.UNUSED_PARAMETER(pVfs);
            return ((microsec + 999)/1000)*1000;
        }

        /*
    ** The following variable, if set to a non-zero value, becomes the result
    ** returned from sqlite3OsCurrentTime().  This is used for testing.
    */
#if SQLITE_TEST
    //    static int sqlite3_current_time = 0;
#endif

        /*
** Find the current time (in Universal Coordinated Time).  Write the
** current time and date as a Julian Day number into prNow and
** return 0.  Return 1 if the time and date cannot be found.
*/

        private static int winCurrentTime(sqlite3_vfs pVfs, ref double prNow)
        {
            //FILETIME ft = new FILETIME();
            /* FILETIME structure is a 64-bit value representing the number of
      100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
      */
            long timeW; /* Whole days */
            long timeF; /* Fractional Days */

            /* Number of 100-nanosecond intervals in a single day */
            const long ntuPerDay =
                10000000*(long) 86400;

            /* Number of 100-nanosecond intervals in half of a day */
            const long ntuPerHalfDay =
                10000000*(long) 43200;

            ///* 2^32 - to avoid use of LL and warnings in gcc */
            //const long max32BitValue =
            //(long)2000000000 + (long)2000000000 + (long)294967296;

            //#if SQLITE_OS_WINCE
            //SYSTEMTIME time;
            //GetSystemTime(&time);
            ///* if SystemTimeToFileTime() fails, it returns zero. */
            //if (!SystemTimeToFileTime(&time,&ft)){
            //return 1;
            //}
            //#else
            //      GetSystemTimeAsFileTime( ref ft );
            //      ft = System.DateTime.UtcNow.ToFileTime();
            //#endif
            //      Helper.UNUSED_PARAMETER( pVfs );
            //      timeW = ( ( (long)ft.dwHighDateTime ) * max32BitValue ) + (long)ft.dwLowDateTime;
            timeW = DateTime.UtcNow.ToFileTime();
            timeF = timeW%ntuPerDay; /* fractional days (100-nanoseconds) */
            timeW = timeW/ntuPerDay; /* whole days */
            timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
            timeF = timeF + ntuPerHalfDay; /* add half a day (from 2305813.5) */
            timeW = timeW + (timeF/ntuPerDay); /* add whole day if half day made one */
            timeF = timeF%ntuPerDay; /* compute new fractional days */
            prNow = timeW + (timeF/(double) ntuPerDay);
#if SQLITE_TEST
      if ( ( sqlite3_current_time.iValue ) != 0 )
      {
        prNow = ( (double)sqlite3_current_time.iValue + (double)43200 ) / (double)86400 + (double)2440587;
      }
#endif
            return 0;
        }


        /*
    ** The idea is that this function works like a combination of
    ** GetLastError() and FormatMessage() on windows (or errno and
    ** strerror_r() on unix). After an error is returned by an OS
    ** function, SQLite calls this function with zBuf pointing to
    ** a buffer of nBuf bytes. The OS layer should populate the
    ** buffer with a nul-terminated UTF-8 encoded error message
    ** describing the last IO error to have occurred within the calling
    ** thread.
    **
    ** If the error message is too large for the supplied buffer,
    ** it should be truncated. The return value of xGetLastError
    ** is zero if the error message fits in the buffer, or non-zero
    ** otherwise (if the message was truncated). If non-zero is returned,
    ** then it is not necessary to include the nul-terminator character
    ** in the output buffer.
    **
    ** Not supplying an error message will have no adverse effect
    ** on SQLite. It is fine to have an implementation that never
    ** returns an error message:
    **
    **   int xGetLastError(sqlite3_vfs pVfs, int nBuf, char *zBuf){
    **     Debug.Assert(zBuf[0]=='\0');
    **     return 0;
    **   }
    **
    ** However if an error message is supplied, it will be incorporated
    ** by sqlite into the error message available to the user using
    ** sqlite3_errmsg(), possibly making IO errors easier to debug.
    */

        private static int winGetLastError(sqlite3_vfs pVfs, int nBuf, ref string zBuf)
        {
            Helper.UNUSED_PARAMETER(pVfs);
            return getLastErrorMsg(nBuf, ref zBuf);
        }

        private static readonly sqlite3_vfs winVfs = new sqlite3_vfs(
            1, /* iVersion */
            -1, //sqlite3_file.Length,      /* szOsFile */
            MAX_PATH, /* mxPathname */
            null, /* pNext */
            "win32", /* zName */
            0, /* pAppData */

            winOpen, /* xOpen */
            winDelete, /* xDelete */
            winAccess, /* xAccess */
            winFullPathname, /* xFullPathname */
            winDlOpen, /* xDlOpen */
            winDlError, /* xDlError */
            winDlSym, /* xDlSym */
            winDlClose, /* xDlClose */
            winRandomness, /* xRandomness */
            winSleep, /* xSleep */
            winCurrentTime, /* xCurrentTime */
            winGetLastError /* xGetLastError */
            );

        /*
    ** Initialize and deinitialize the operating system interface.
    */

        private static int sqlite3_os_init()
        {
            sqlite3_vfs_register(winVfs, 1);
            return StatusCode.SQLITE_OK;
        }

        private static int sqlite3_os_end()
        {
            return StatusCode.SQLITE_OK;
        }

#endif
        // * SQLITE_OS_WIN */
        //
        //          Windows DLL definitions
        //

        private const int NO_ERROR = 0;

        /// <summary>
        /// Basic locking strategy for Console/Winform applications
        /// </summary>
        private class LockingStrategy
        {
#if !SQLITE_SILVERLIGHT
            [DllImport("kernel32.dll")]
            private static extern bool LockFileEx(HANDLE hFile, uint dwFlags, uint dwReserved,
                                                  uint nNumberOfBytesToLockLow, uint nNumberOfBytesToLockHigh,
                                                  [In] ref NativeOverlapped lpOverlapped);

            private const int LOCKFILE_FAIL_IMMEDIATELY = 1;
#endif

            public virtual void LockFile(sqlite3_file pFile, long offset, long length)
            {
#if !SQLITE_SILVERLIGHT
                pFile.fs.Lock(offset, length);
#endif
            }

            public virtual int SharedLockFile(sqlite3_file pFile, long offset, long length)
            {
#if !SQLITE_SILVERLIGHT
                Debug.Assert(length == Global.SHARED_SIZE);
                Debug.Assert(offset == Global.SHARED_FIRST);
                var ovlp = new NativeOverlapped();
                ovlp.OffsetLow = (int) offset;
                ovlp.OffsetHigh = 0;
                ovlp.EventHandle = IntPtr.Zero;

                return LockFileEx(pFile.fs.Handle, LOCKFILE_FAIL_IMMEDIATELY, 0, (uint) length, 0, ref ovlp) ? 1 : 0;
#else
        return 1;
#endif
            }

            public virtual void UnlockFile(sqlite3_file pFile, long offset, long length)
            {
#if !SQLITE_SILVERLIGHT
                pFile.fs.Unlock(offset, length);
#endif
            }
        }

        /// <summary>
        /// Locking strategy for Medium Trust. It uses the same trick used in the native code for WIN_CE
        /// which doesn't support LockFileEx as well.
        /// </summary>
        private class MediumTrustLockingStrategy : LockingStrategy
        {
            public override int SharedLockFile(sqlite3_file pFile, long offset, long length)
            {
#if !SQLITE_SILVERLIGHT
                Debug.Assert(length == Global.SHARED_SIZE);
                Debug.Assert(offset == Global.SHARED_FIRST);
                try
                {
                    pFile.fs.Lock(offset + pFile.sharedLockByte, 1);
                }
                catch (IOException)
                {
                    return 0;
                }
#endif
                return 1;
            }
        }
    }

    internal static class HelperMethods
    {
        public static bool IsRunningMediumTrust()
        {
            // placeholder method
            // this is where it needs to check if it's running in an ASP.Net MediumTrust or lower environment
            // in order to pick the appropriate locking strategy
#if SQLITE_SILVERLIGHT
      return true;
#else
            return false;
#endif
        }
    }
}